package jp.tkym.labs.proc;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 
 * @author takayama
 */
public class PreparedMessageProcesser implements Serializable{
	/** serialVersionUID */
	private static final long serialVersionUID = -1843510919855064438L;
	
	MainInvoker asMain(PreparedMain main) throws PreparedMessageException{
		try {
			return new MainInvoker(Class.forName(main.className())).properties(main.properties());
		} catch (Exception e) {
			throw new PreparedMessageException("exception of PrecallMessageUtil.asMain ", e);
		}
	}
	
	class MainInvoker{
		private Class<?> clazz;
		private Map<String, String> properties = new HashMap<String, String>();
		
		MainInvoker(Class<?> clazz) {
			this.clazz = clazz;
		}
		
		MainInvoker properties(Map<String, String> map){
			this.properties.putAll(map);
			return this;
		}
		
		void invoke(String... args) throws Exception{
			Method mainMethod = clazz.getMethod("main", new Class<?>[]{String[].class});
			for(String key : properties.keySet()) 
				if(properties.get(key) != null)
					System.setProperty(key, properties.get(key));
			mainMethod.invoke(null, new Object[]{args});
		}
	}
	
	@SuppressWarnings("unchecked")
	<T extends Runnable> T asRunnable(PrecallTask task) throws PreparedMessageException{
		try {
			Object instance = Class.forName(task.className()).newInstance();
			return (T) instance;
		} catch (Exception e) {
			throw new PreparedMessageException("exception of PrecallMessageUtil.asRunnable ",e);
		}
	}
	
	class PreparedMessageException extends Exception{
		/** serialVersionUID */
		private static final long serialVersionUID = 2668467454422471874L;
		PreparedMessageException(String s, Throwable t){ super(s, t); }
		PreparedMessageException(Throwable t){ super(t); }
	}
	
	PreparedExit createExit(){
		return new PreparedExit();
	}
	
	<T> PreparedMain createMain(String className, Map<String, String> properties){
		return new PreparedMain(className, properties);
	}
	
	<T extends Runnable> PrecallTask createTask(String className){
		return new PrecallTask(className);
	}
	
	class PreparedExit implements PreparedMessage{
		/** serialVersionUID */
		private static final long serialVersionUID = -4193598806197497562L;
	}
	
	class PreparedMain implements PreparedMessage{
		/** serialVersionUID */
		private static final long serialVersionUID = 1703709493170119411L;
		private String className;
		private Map<String, String> properties; 
		PreparedMain(String className, Map<String, String> properties){
			this.className = className;
			this.properties = properties;
		}
		PreparedMain(String className){
			this.className = className;
		}
		String className(){ return className; }
		Map<String, String> properties(){ return properties; }
	}
	
	class PrecallTask implements PreparedMessage{
		/** serialVersionUID */
		private static final long serialVersionUID = 4093761460232985016L;
		private String className;
		PrecallTask(String className){
			this.className = className;
		}
		String className(){ return className; }
	}
	interface PreparedMessage extends Serializable{}
}
